﻿#region Copyright(c) 2006 ZO, All right reserved.
// -----------------------------------------------------------------------------
// Copyright(c) 2006 ZO, All right reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
//   1.  Redistribution of source code must retain the above copyright notice,
//       this list of conditions and the following disclaimer.
//   2.  Redistribution in binary form must reproduce the above copyright
//       notice, this list of conditions and the following disclaimer in the
//       documentation and/or other materials provided with the distribution.
//   3.  The name of the author may not be used to endorse or promote products
//       derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// -----------------------------------------------------------------------------
#endregion


#region Using directives

using System;
using ZO.SmartCore.IO;
using ZO.SmartCore.Xml;

#endregion

namespace ZO.SmartCore.Configuration
{
    /// <summary>
    /// Xml Configuration Format specified by library
    /// </summary>
    public class XmlConfigurationFormat : IConfigurationFormat
    {

        #region Constructors

        #endregion

        #region Destructor

        #endregion

        #region Fields
        private Section _DefaultSection;

        #endregion

        #region Events

        #endregion

        #region Operators

        #endregion

        #region Properties

        #endregion

        #region Methods

        #endregion

        #region IConfigurationFormat Members

        /// <summary>
        /// Get The Name of Format used by the Formatter
        /// </summary>
        /// <value>format name.</value>
        public virtual string Name
        {
            get
            {
                return "Xml";
            }
        }

        /// <summary>
        /// Gets the default section.
        /// </summary>
        /// <value>The default section.</value>
        public virtual Section DefaultSection
        {
            get
            {
                if (_DefaultSection == null)
                {
                    _DefaultSection = new Section("configuration", "configuration file");
                }
                return _DefaultSection;
            }
        }

        /// <summary>
        /// Write the specified section to stream and return it;
        /// </summary>
        /// <returns>stream containing the section</returns>
        public virtual StringStream Write()
        {

            Document xmlDoc = new Document();

            if (!String.IsNullOrEmpty(DefaultSection.Comment))
            {
                xmlDoc.AddChild(new Comment(DefaultSection.Comment));
            }

            Element parentElement = new Element(DefaultSection.Name);
            xmlDoc.AddChild(parentElement);

            WriteSection(parentElement, DefaultSection);


            return new StringStream(xmlDoc.ToString());
        }

        /// <summary>
        /// Writes the section.
        /// </summary>
        /// <param name="parent">The parent.</param>
        /// <param name="section">The section.</param>
        private static void WriteSection(Element parent, Section section)
        {
            if (section == null)
            {
                return;
            }
            foreach (SectionKey key in section.Keys)
            {
                if (!String.IsNullOrEmpty(key.Comment))
                {
                    parent.AddChild(new Comment(key.Comment));
                }
                Element childKeyElement = parent.AddChildElement("key");
                childKeyElement.Attributes.Add("name", key.Name);
                childKeyElement.Attributes.Add("value", key.Value);
            }

            foreach (Section section1 in section.Sections)
            {
                if (!String.IsNullOrEmpty(section1.Comment))
                {
                    parent.AddChild(new Comment(section1.Comment));
                }
                Element childElement = parent.AddChildElement("section");
                childElement.Attributes.Add("name", section1.Name);
                WriteSection(childElement, section1);
            }
        } // method

        /// <summary>
        /// Reads the specified contents.
        /// </summary>
        /// <param name="contents">The contents.</param>
        public virtual void Read(StringStream contents)
        {
            if (contents == null)
            {
                return;
            }


            if (contents.Length == 0)
            {
                return;
            }

            string xml = contents.ToString();

            Document xmlDoc = new Document();

            xmlDoc.LoadXml(xml);



            if (xmlDoc.ChildNodes.Count != 0)
            {
                string comment = "";
                if (xmlDoc.ChildNodes[0].NodeType == NodeType.Comment)
                {
                    comment = xmlDoc.ChildNodes[0].Value;
                }
                Element parentElement = xmlDoc.DocumentElement;

                if (parentElement.Name != DefaultSection.Name)
                {
                    return;
                }

                this._DefaultSection = new Section(parentElement.Name, comment);

                ReadSection(parentElement, _DefaultSection);

            }

        }

        /// <summary>
        /// Reads the section.
        /// </summary>
        /// <param name="sectionElement">The parent.</param>
        /// <param name="currentSection">The current section.</param>
        private static void ReadSection(Element sectionElement, Section currentSection)
        {

            if (currentSection == null)
            {
                return;
            }

            if (sectionElement == null)
            {
                return;
            }
            string comment = "";

            foreach (Node node in sectionElement.ChildNodes)
            {
                if (node.NodeType == NodeType.Comment)
                {
                    comment = node.Value;
                    continue;
                } // if

                if (node.NodeType == NodeType.Element)
                {
                    Element temp = (Element)node;

                    if ((temp.Name != "section") && (temp.Name != "key"))
                    {
                        continue;
                    } // if


					if ((temp.Name == sectionElement.Name) || (temp.Name == "section"))
                    {
                        string sectionName = temp.GetAttribute("name");

                        Section newSection = null;
                        if (!String.IsNullOrEmpty(sectionName))
                        {
                            newSection = new Section(sectionName, comment);
                        }

                        if (newSection != null)
                        {
                            currentSection.Sections.Add(newSection);
                            ReadSection(temp, newSection);
                        }

                        comment = "";
                    }

                    if (temp.Name == "key")
                    {
                        string keyName = temp.GetAttribute("name");
                        string keyValue = temp.GetAttribute("value");
                        SectionKey newKey = null;

                        if (!String.IsNullOrEmpty(keyName))
                        {
                            newKey = new SectionKey(keyName, keyValue, comment);
                        }

                        if (newKey != null)
                        {
                            currentSection.Keys.Add(newKey);
                        }

                        comment = "";
                    } // if

                } // if


            } // foreach 
        } // ReadSection
        #endregion

    }
}
